package ca.seia.comp6521.a2.itemsetstorage;

import gnu.trove.iterator.TObjectIntIterator;
import gnu.trove.map.TObjectIntMap;
import gnu.trove.map.hash.TObjectCharHashMap;
import gnu.trove.map.hash.TObjectIntHashMap;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.github.jamm.MemoryMeter;

import ca.seia.comp6521.a2.io.DataFileWriter;

import com.javabi.sizeof.MemoryUtil;

public class Triples implements PairStorage{
	
	private TObjectIntMap<IntPair> countMap;
	
	public Triples() {
		this.countMap = new TObjectIntHashMap<IntPair>();
		
	}

	@Override
	public void addCount(int value1, int value2) {
//		System.out.println("size of elements " + this.countMap.size());
		this.countMap.adjustOrPutValue(new IntPair(value1, value2), 1, 1);
		//System.out.println("Size of free memory " + MemoryUtil.free());
//		if (this.countMap.size() == 102877) {
//			System.out.println("reached max flushing content");
//			this.countMap = null;
//			this.countMap = new TObjectIntHashMap<IntPair>();
//		}
	}

	@Override
	public int getPairCount(int value1, int value2) {
		return this.countMap.get(new IntPair(value1,value2));
	}
	
	public void removeInfrequentPairs(int support) {
		for (Object pair :this.countMap.keys() ) {
			if(this.countMap.get(pair) < support) {
				this.countMap.remove(pair);
			}
		}
	}
	
	public void removeInfrequentPairsAndWriteToDisk(int support, DataFileWriter fileWriter) throws IOException {

		for (TObjectIntIterator iterator = countMap.iterator(); iterator.hasNext();) {
			iterator.advance();
			if ( iterator.value() >=  support) {
				fileWriter.writeItems((ExternilizableItems) iterator.key(), iterator.value());
			} else {
				iterator.remove();
			}
		}
	}
	
	public void writeToDisk(int support, DataFileWriter fileWriter) throws IOException {
		
		TObjectIntIterator iterator = countMap.iterator();
		int mapSize = countMap.size();
		for (int i = mapSize; i-- > 0;) {
			iterator.advance();
			fileWriter.writeItems((ExternilizableItems) iterator.key(), iterator.value());
		}
		fileWriter.close();
	}
	
	public List<IntItems> generateCandidateTriplets() {
		IntPair[] keys = (IntPair[]) this.countMap.keys(new IntPair[0]);
		
		Arrays.sort(keys);
		List<IntItems> triplets = new ArrayList<IntItems>();
		
		int keyLength = keys.length;
		for(int keyIndex = 0 ; keyIndex < keyLength ; keyIndex++) {
			for(int secondPairIndex = keyIndex + 1; secondPairIndex < keyLength ; secondPairIndex++) {
				IntItems triplet = IntItems.generateCandidateTriplet(keys[keyIndex], keys[secondPairIndex]);
				if(triplet == null) {
					break;
				} else {
					triplets.add(triplet);
				}
			}
		}
		return triplets;
	}
	
	@Override
	public String toString() {
		return this.countMap.toString() + " count of pairs is = " + this.countMap.size();
	}

	public static void main(String[] args) throws IllegalAccessException {
		Triples triples = new Triples();
		triples.addCount(1, 2);
		TObjectCharHashMap<IntPair> optMap = new TObjectCharHashMap<IntPair>();
		Map<IntPair,Character> intMap = new HashMap<IntPair, Character>();
		intMap.put(new IntPair(1, 2), '1');
		MemoryMeter memMeter = new MemoryMeter();
//		System.out.println("Java collection size of hashmap " + MemoryUtil.sizeOf(intMap));
		System.out.println("Java collection size of hashmap " + memMeter.measureDeep(intMap));
//		triples.addCount(1, 2);
//		triples.addCount(1, 2);
//		triples.addCount(1, 2);
//		triples.addCount(1, 2);
		triples.addCount(2, 2);
		triples.addCount(3, 2);
		
		for(int i= 0; i< 7 ; i++) {
			for(int j=i+1 ; j<7;j++){
				System.out.println("( " + i + ", " + j+")");
				triples.addCount(i, j);
				optMap.put(new IntPair(i,j), '1');
				intMap.put(new IntPair(i, j), '1');
			}
		}
		
//		int[] triple = new int[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
//		short[] tripleShort = new short[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
//		char[] tripleChar = new char[]{'1','2','3','4','5','6','7','8','9',10,11,12,13,14,15,16,17,18,19};
//		System.out.println("int value of char is " + (int)tripleChar[18]);
		
		int[] triple = new int[]{1,2,3,4};
		short[] tripleShort = new short[]{1,2,3,4};
		char[] tripleChar = new char[]{'1','2','3','4'};
		

		
//		System.out.println("size of int {1,2,3} array = " + MemoryUtil.sizeOf(triple));
//		System.out.println("size of char {1,2,3} array = " + MemoryUtil.sizeOf(tripleChar));
//		System.out.println("size of short {1,2,3} array = " + MemoryUtil.sizeOf(tripleShort));
//		
//		System.out.println("get pair (1,2) " + triples.getPairCount(198, 2));
//		System.out.println("size of map " + intMap.size());
//		System.out.println("Size of triples wich char as key = " + MemoryUtil.sizeOf(optMap));
//		System.out.println("Size of triples is = " + MemoryUtil.sizeOf(triples));
//		System.out.println("Java collection size of hashmap " + MemoryUtil.sizeOf(intMap));
		
		System.out.println("size of int {1,2,3} array = " +  memMeter.measureDeep(triple));
		System.out.println("size of char {1,2,3} array = " +  memMeter.measureDeep(tripleChar));
		System.out.println("size of short {1,2,3} array = " +  memMeter.measureDeep(tripleShort));
		
		System.out.println("get pair (1,2) " + triples.getPairCount(198, 2));
		System.out.println("size of map " + intMap.size());
		System.out.println("Size of optMap with char as key = " +  memMeter.measureDeep(optMap));
		System.out.println("Size of triples is = " +  memMeter.measureDeep(triples));
		System.out.println("Java collection size of hashmap " +  memMeter.measureDeep(intMap));
		
		IntItems tripletOne = new IntItems(1,2,3,4);
		CharItems tripletchar = new CharItems('1','2','3','4');
		IntTriplet intTriplet = new IntTriplet(1, 2,3);
		CharTriplet charTriplet = new CharTriplet(1, 2,3);
		
		System.out.println("size of triple Int is " + memMeter.measureDeep(tripletOne));
		System.out.println("size of triplet char is " + memMeter.measureDeep(tripletchar));
		System.out.println("size of triplet prim Int is " + memMeter.measureDeep(intTriplet));
		System.out.println("size of triplet prim char is " + memMeter.measureDeep(charTriplet));
	}
}
